#include "aerial\Core\Core.h"

#include "aerial\Core\base.h"
#include "aerial\Object\Object.h"

#include <iostream>

using namespace std;

namespace air {
	Core* Core::instance = NULL;

	/**
	 * @brief create an instance of this class and return its pointer, will not create if such an instance already exists
	 * 
	 * @return a pointer to an instance of this class
	 */
	Core* Core::create() 
	{
		if (instance == NULL) instance = new Core();
		return instance;
	}

	/**
	 * @brief Constructor. Cannot be called by user. Called by static Core::create() factory;
	 */
	Core::Core(): hge(NULL)
	{
	}

	/*
	 * @brief Core desctructor.
	 */
	Core::~Core()
	{
		hgeResMan.Purge();
		if (hge) {
			hge->System_Shutdown();
			hge->Release();
		}
	}

	/**
	 * @brief initialize with collected info. TODO let user set the mutable info
	 *
	 * @return true when successfully. otherwise false, will need do be released when fail
	 */
	//TODO ErrorMessage
	bool Core::initiate()
	{
		// graphic component initialization
		hge = hgeCreate(HGE_VERSION);
		
		// mutable configurations may be specified by users
		hge->System_SetState(HGE_FPS, 50);
		hge->System_SetState(HGE_WINDOWED, true);
		hge->System_SetState(HGE_USESOUND, false);
		hge->System_SetState(HGE_SCREENWIDTH, 800);
		hge->System_SetState(HGE_SCREENHEIGHT, 600);

		// immutable
		hge->System_SetState(HGE_FRAMEFUNC, Core::frameFunc);
		hge->System_SetState(HGE_RENDERFUNC, Core::renderFunc);
		hge->System_SetState(HGE_TITLE, "A.I.R");
		hge->System_SetState(HGE_LOGFILE, "air.hge.log");
		hge->System_SetState(HGE_SCREENBPP, 32);
		hge->System_SetState(HGE_HIDEMOUSE, false);
		hge->System_SetState(HGE_DONTSUSPEND, true);
		hge->System_SetState(HGE_SHOWSPLASH, false);
		

		if (!hge->System_Initiate()) return false;
		if (!loadResource()) return false;
		
		scenes.setHge(hge);
		scenes.setResourceManager(&hgeResMan);
		scenes.setNetIO(&netIO);
		return true;
	}

	/**
	 * @brief load and parse resource script. TODO let the user provide the script
	 *
	 * @return true when success, otherwise false.
	 */
	bool Core::loadResource()
	{
		hgeResMan.ChangeScript("aeria.res");
		if (strcmp(hge->System_GetErrorMessage(), ""))
		{
			MessageBoxA(NULL,hge->System_GetErrorMessage(), "ERROR", MB_OK);
			return false;
		}
		if (!hgeResMan.Precache())
		{
#ifndef A
			cout << "Error handling hgeresourcemanager\n";
#else 
			MessageBox(NULL, LPWSTR(hge->System_GetErrorMessage()), L"A.I.R", MB_OK);
#endif
			return false;
		}
		return true;
	}

	/**
	 * @brief set the initial scene for engine. can only be called after Core::initiate(). only last time works if called for many times
	 *
	 * @param a pointer to iScene
	 *
	 * @return true when iScene is initialized successfully
	 */
	bool Core::addScene(IScene* iScene)
	{
		return scenes.initializeScene(iScene);
		return true;
	}

	/**
	 * @brief start all the components
	 */
	void Core::start()
	{
		scenes.start();
		hge->System_Start();
	}

	/**
	 * @brief call Core desctructor
	 */
	void Core::release() 
	{
		delete instance;
		instance = NULL;
	}

	/**
	 * @brief logic process function hge will call every frame
	 *
	 * @param dt time elapsed since last called
	 *
	 * @return bool false for continue running. true for end.
	 */
	bool Core::frameFunc() {
		float dt = instance->hge->Timer_GetDelta();
		return instance->scenes.update(dt);
		return true;
	}

	/**
	 * @brief render function hge will call every frame
	 *
	 * @param dt same with frameFunc(float dt)
	 *
	 * @return same with frameFunc(float dt)
	 */
	bool Core::renderFunc() {
		float dt = instance->hge->Timer_GetDelta();
		instance->hge->Gfx_BeginScene();
		instance->scenes.render(dt);
		instance->hge->Gfx_EndScene();
		return false;
	}
}
